package rules;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import managers.ComponentManager;
import managers.SemanticsManager;

import org.jdom2.Element;

import components.Component;
import components.Leaf;
import features.Feature;

public abstract class Action {

	public static final String DELETE_CONST = "deleteConstituent"; 
	public static final String MOVE_CONST = "moveConstituent"; 
	public static final String COPY_CONST = "copyConstituent";
	public static final String ADD_SEM = "addSemantics"; 
	public static final String ADD_FEAT = "addFeature";

	public static final String DELETE_FEAT = "deleteFeature"; 
	public static final String ORDER_SUBCONST = "orderSubconstituents";
	public static final String ADD_TRANS = "addTrans";
	public static final String CHANGE_TRANS = "changeTrans";
	public static final String DELETE_TRANS = "deleteTrans";
	public static final String INSERT_FORM = "insertForm";
	
	private String type;
	
	public void setType(String type){
		this.type = type;
	}
	public String getType(){
		return type;
	}
	
	public Element getXMLElement(){	
		Element xmlElement = new Element("action");
		
		xmlElement.setAttribute("type", type);
		xmlElement = insertArguments(xmlElement);
		
		return xmlElement;
	}
	
	public static Action createInstance(Element element) {
		Action newAction = null;
		
		String type = element.getAttributeValue("type");

		if(type.equals(DELETE_CONST))
			newAction = new deleteConstituent();
		else if(type.equals(MOVE_CONST))
			newAction = new moveConstituent();
		else if(type.equals(COPY_CONST))
			newAction = new copyConstituent();
		else if(type.equals(ADD_SEM))
			newAction = new addSemantics();
		else if(type.equals(ADD_FEAT))
			newAction = new addFeature();
		else if(type.equals(DELETE_FEAT))
			newAction = new deleteFeature();
		else if(type.equals(ORDER_SUBCONST))
			newAction = new orderSubconstituents();
		else if(type.equals(ADD_TRANS))
			newAction = new addTrans();
		else if(type.equals(CHANGE_TRANS))
			newAction = new changeTrans();
		else if(type.equals(DELETE_TRANS))
			newAction = new deleteTrans();
		else if(type.equals(INSERT_FORM))
			newAction = new insertForm();

		newAction.parseElement(element);
		
		if(newAction != null)
			newAction.setType(type);
		
		return newAction;
	}
	
	public abstract Element insertArguments(Element input);
	public abstract void applyAction(HashMap<Integer, Component> tagMap);
	public abstract void parseElement(Element input);
	
}

class deleteConstituent extends Action{

	int deleteTag; // refers to component to be deleted
	
	@Override
	public void applyAction(HashMap<Integer, Component> tagMap){
		// TODO: dsad
	}

	@Override
	public Element insertArguments(Element input) {
		Element argument = new Element("argument");
		argument.setAttribute("tag", Integer.toString(deleteTag));
		input.addContent(argument);

		return input;
	}

	@Override
	public void parseElement(Element input) {
			deleteTag = Integer.parseInt(input.getChild("argument").getAttributeValue("tag"));
		
	}
}

class moveConstituent extends Action{

	int sourceTag; // refers to source location
	int destinationTag; // refers to destination location
	
	@Override
	public void applyAction(HashMap<Integer, Component> tagMap){
		// TODO Auto-generated method stub
		
	}

	@Override
	public Element insertArguments(Element input) {
		Element argument = new Element("argument_1");
		
		argument.setAttribute("tag", Integer.toString(sourceTag));
		input.addContent(argument);

		argument = new Element("argument_2");
		argument.setAttribute("tag", Integer.toString(destinationTag));
		
		input.addContent(argument);

		return input;
	}

	@Override
	public void parseElement(Element input) {
		sourceTag = Integer.parseInt(input.getChild("argument_1").getAttributeValue("tag").toString());
		destinationTag = Integer.parseInt(input.getChild("argument_2").getAttributeValue("tag").toString());
	}
}

class copyConstituent extends Action{

	int sourceTag; // refers to source location
	int destinationTag; // refers to destination location
	
	@Override
	public void applyAction(HashMap<Integer, Component> tagMap){
		// TODO Auto-generated method stub
		
	}

	@Override
	public Element insertArguments(Element input) {
		Element argument = new Element("argument_1");
		
		argument.setAttribute("tag", Integer.toString(sourceTag));
		input.addContent(argument);

		argument = new Element("argument_2");
		argument.setAttribute("tag", Integer.toString(destinationTag));
		
		input.addContent(argument);

		return input;
	}

	@Override
	public void parseElement(Element input) {
		sourceTag = Integer.parseInt(input.getChild("argument_1").getAttributeValue("tag").toString());
		destinationTag = Integer.parseInt(input.getChild("argument_2").getAttributeValue("tag").toString());	
	}
}

class addSemantics extends Action{

	int tag; // refers to component
	Component semantics;
	
	@Override
	public void applyAction(HashMap<Integer, Component> tagMap){
		tagMap.get(tag).getChildren().addChild(semantics);
	}

	@Override
	public Element insertArguments(Element input) {
		Element argument;
		
		argument = new Element("argument");
		argument.setAttribute("tag", Integer.toString(tag));
		input.addContent(argument);

		argument = new Element("argument");
		argument.addContent(semantics.generateXMLElement());
		input.addContent(argument);

		return input;
	}

	@Override
	public void parseElement(Element input) {
		List<Element> arglist = input.getChildren();
		tag = Integer.parseInt(arglist.get(0).getAttributeValue("tag").toString());
		semantics = Component.createInstance(arglist.get(1).getChildren().get(0));
		//System.out.println(((Leaf)semantics).getConcept());
	}
}

class addFeature extends Action{

	int tag; 
	Feature feature; // new Feature
	
	@Override
	public void applyAction(HashMap<Integer, Component> tagMap){
		tagMap.get(tag).getFeatureList().setFeature(feature);
	}

	@Override
	public Element insertArguments(Element input) {
		Element argument;
		
		argument = new Element("argument");
		argument.setAttribute("tag", Integer.toString(tag));
		input.addContent(argument);

		argument = new Element("argument");
		argument.addContent(feature.generateXMLElement());
		input.addContent(argument);

		return input;
	}

	@Override
	public void parseElement(Element input) {
		List<Element> arglist = input.getChildren();
		tag = Integer.parseInt(arglist.get(0).getAttributeValue("tag").toString());
		feature = Feature.createInstance(arglist.get(1).getChild("feature"));
	}
}

class deleteFeature extends Action{

	int tag;
	Feature feature;
	
	@Override
	public void applyAction(HashMap<Integer, Component> tagMap){
		// TODO Auto-generated method stub
		
	}

	@Override
	public Element insertArguments(Element input) {
		Element argument = new Element("argument_1");
		
		argument.setAttribute("tag", Integer.toString(tag));
		input.addContent(argument);

		argument = new Element("argument_2");
		argument.addContent(feature.generateXMLElement());
		
		input.addContent(argument);

		return input;
	}

	@Override
	public void parseElement(Element input) {
		tag = Integer.parseInt(input.getChild("argument_1").getAttributeValue("tag").toString());
		feature = Feature.createInstance(input.getChild("argument_2"));
	}
}

class orderSubconstituents extends Action{

	Integer parentTag;
	ArrayList<Integer> tagList;
	
	@Override
	public void applyAction(HashMap<Integer, Component> tagMap){
		Component parent = tagMap.get(parentTag);
		
		ArrayList<Component> unsorted = parent.getChildren().getChildren();
		ArrayList<Component> sorted = new ArrayList<Component>();
		
		for(Integer tag : tagList){
			sorted.add(tagMap.get(tag));
			unsorted.remove(tagMap.get(tag));
		}
		
		for(Component excess : unsorted)
			sorted.add(excess);
		
		parent.getChildren().setChildren(sorted);
	}

	@Override
	public Element insertArguments(Element input) {
		Element argument;
		
		argument = new Element("argument");
		argument.setAttribute("tag", Integer.toString(parentTag));
		input.addContent(argument);
		
		for(int i = 0; i < tagList.size(); i++){
			argument = new Element("argument");
			argument.setAttribute("tag", Integer.toString(tagList.get(i)));
			input.addContent(argument);
			
		}

		return input;
	}

	@Override
	public void parseElement(Element input) {
		List<Element> arglist = input.getChildren();
		parentTag = Integer.parseInt(arglist.remove(0).getAttributeValue("tag").toString());
		
		tagList = new ArrayList<Integer>();
		for(Element element : input.getChildren())
			tagList.add(Integer.parseInt(element.getAttributeValue("tag").toString()));
		
	}
}

class addTrans extends Action{
	
	int tag;

	@Override
	public void applyAction(HashMap<Integer, Component> tagMap){
		// TODO Auto-generated method stub
		
	}

	@Override
	public Element insertArguments(Element input) {
		Element argument = new Element("argument");
		
		argument.setAttribute("tag", Integer.toString(tag));
		
		input.addContent(argument);

		return input;
	}

	@Override
	public void parseElement(Element input) {
		tag = Integer.parseInt(input.getChild("argument").getAttributeValue("tag").toString());	
	}
}

class changeTrans extends Action{

	int tag;
	
	@Override
	public void applyAction(HashMap<Integer, Component> tagMap){
		// TODO Auto-generated method stub
		
	}

	@Override
	public Element insertArguments(Element input) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void parseElement(Element input) {
		tag = Integer.parseInt(input.getChild("argument").getAttributeValue("tag").toString());
	}
	
}

class deleteTrans extends Action{

	int tag;
	
	@Override
	public void applyAction(HashMap<Integer, Component> tagMap){
		// TODO Auto-generated method stub
		
	}

	@Override
	public Element insertArguments(Element input) {
		Element argument = new Element("argument");
		
		argument.setAttribute("tag", Integer.toString(tag));
		
		input.addContent(argument);

		return input;
	}

	@Override
	public void parseElement(Element input) {
		tag = Integer.parseInt(input.getChild("argument").getAttributeValue("tag").toString());
	}
	
}

class insertForm extends Action{

	int tag;
	
	@Override
	public void applyAction(HashMap<Integer, Component> tagMap){
		// TODO Auto-generated method stub
		
	}

	@Override
	public Element insertArguments(Element input) {
		Element argument = new Element("argument");
		
		argument.setAttribute("tag", Integer.toString(tag));
		
		input.addContent(argument);

		return input;
	}

	@Override
	public void parseElement(Element input) {
		tag = Integer.parseInt(input.getChild("argument").getAttributeValue("tag").toString());
	}
	
}


/*
 * 
deleteConstituent(tag)
moveConstituent(tag,tag)
copyConstituent(tag,tag)

addSemantics(tag, component)
addFeature(tag, feature)
changeFeature(tag, feature-value)

deleteFeature(tag, feature-name)
orderSubconstituents(List<tag>)
addTrans(tag,thing)

changeTrans(tag,thing,thing)
deleteTrans(tag,thing)
insertForm(tag,form)
 * 
 * 
 * 
 * 
 * 
 * */

/*
 * 
 * //public static final String STANDARD = "standard"; 
		
		//if(type.equals(STANDARD))
		//	newAction = new standard();
		//else 
		
		
class standard extends Action{

	ArrayList<Component> components; // refers to component to be deleted
	HashMap<Integer, Component> componentMap;
	
	@Override
	public void applyAction(Component input) {
		// TODO Auto-generated method stub
	}

	@Override
	public Element insertArguments(Element input) {
		
		if(components != null && components.size() != 0)
			for(Component component : components)
				if(ComponentManager.getInstance().isLeaf(component.getName()))
					input.addContent(((RuleInputLeaf)component).generateXMLElement());
				else
					input.addContent(((RuleInputPhrase)component).generateXMLElement());

		return input;
	}
	
	public void addTagComponentPair(Integer tag, Component c){
		if(componentMap == null)
			componentMap = new HashMap<Integer, Component>();
		
		componentMap.put(tag, c);
	}

	@Override
	public void parseElement(Element input) {
		components = new ArrayList<Component>();
		
		for(Element element : input.getChildren())
			components.add(createOutput(element));
	}
	
	public Component createOutput(Element input){
		
		int tag = Integer.parseInt(input.getAttributeValue("tag")); 
		boolean isOptional = Boolean.parseBoolean(input.getAttributeValue("isOptional"));
			
		String componentName = input.getAttributeValue("name");
			
			if(ComponentManager.getInstance().isLeaf(componentName)){
				RuleInputLeaf leaf = new RuleInputLeaf(input);
				
				leaf.setOptional(isOptional);
				leaf.setTag(tag);
				
				addTagComponentPair(tag, leaf);
				
				return leaf;
			}
			
			else{
				List<Element> childrenElements = (List<Element>)input.getChildren(SemanticsManager.COMPONENT);
				if(childrenElements == null)
					childrenElements = new ArrayList<Element>();
	
				RuleInputPhrase phrase = new RuleInputPhrase(input);
					
				phrase.setOptional(isOptional);
				phrase.setTag(tag);
					
				if(phrase.getFeature("Type") != null)
					System.out.println("AGHGGG " + phrase.getFeature("Type").getValue());
					
				for(Element child: childrenElements)
					phrase.addChild(createOutput(child));
					
				addTagComponentPair(tag, phrase);
					
				return phrase;
			}
	}
}
*/
 